#ifndef EXIF_READER_H__c72b6257_917a_40bd_8880_3266b410efbf
#define EXIF_READER_H__c72b6257_917a_40bd_8880_3266b410efbf

#include "stdafx.h"

enum TAG_TYPE
{
	TYPE_BYTE = 1,		// An 8-bit unsigned integer
	TYPE_ASCII,			// A ASCII string which is terminated with NULL
	TYPE_SHORT,			// A 16-bit unsigned integer
	TYPE_LONG,			// A 32-bit unsigned integer
	TYPE_RATIONAL,		// Two LONGs. The first is the numerator and the second is the denominator
	TYPE_UNDEFINED = 7,	// An 8-bit byte that can take any value depending on the field definition
	TYPE_SLONG = 9,		// A 32-bit signed integer
	TYPE_SRATIONAL		// Two SLONGs. The first is the numerator and the second is the denominator
};

typedef struct tagTIFFTag
{
	byte Tag[2];
	byte Type[2];
	byte Count[4];
	byte ValueOffset[4];
}IFD0Tag, TIFFTag, ExifTag, GPSInfoTag;

struct Tag
{
	unsigned int tag;
	unsigned int type;
	unsigned int count;
	unsigned int offset;
	byte value[4];
};

enum IFD0_TAGS
{
	CAMERA_MAKER = 0x10F,		// Image input equipment manufacturer
	CAMERA_MODEL = 0x110,		// Image input equipment model
	ORIENTATION = 0x0112,		// Orientation of image
	HORIZONTAL_RESOLUTION = 0x011A,	// Image resolution in width direction
	VERTICAL_RESOLUTION = 0x011B,	// Image resolution in height direction
	RESOLUTION_UNIT = 0x0128,	// Unit of X and Y resolution
	PROGRAM_NAME = 0x0131,		// Software used
	DATA_TOKEN = 0x0132,		// File change date and time
	YCBCR_POSITIONING = 0x0213,	// Y and C positioning
	EXIF_IFD_POINTER = 0x8769,	// A pointer to Exif IFD
	GPS_INFO_IFD_POINTER = 0x8825	// A pointer to GPS Info IFD
};

enum EXIF_IFD_TAGS
{
	EXPOSURE_TIME = 0x829A,		// Exposure time
	F_STOP = 0x829D,			// F number
	EXPOSURE_PROGRAM = 0x8822,	// Exposure program
	ISO_SPEED = 0x8827,			// ISO speed rating
	EXIF_VERSION = 0x9000,		// Exif version
	DATETIME_ORIGINAL = 0x9003,	// Date and time of original data generation
	DATETIME_DIGITIZED = 0x9004,	// Date and time of digital data generation
	COMPONENTS_CONFIGURATION = 0x9101,	// Meaning of each component
	SHUTTER_SPEED = 0x9201,		// Shutter speed
	APERTURE = 0x9202,			// Aperture
	BRIGHTNESS = 0x9203,		// Brightness
	EXPOSURE_BIAS = 0x9204,		// Exposure bias
	METERING_MODE = 0x9207,		// Metering mode
	FLASH_TAG = 0x9209,			// Flash
	FOCAL_LENGTH = 0x920A,		// Lens focal length
	SUBJECT_AREA = 0x9214,		// Subject area
	MAKER_NOTE = 0x927C,		// Manufacturer notes
	SUBSECOND_DATETIME_ORIGINAL = 0x9291,	// DateTimeOriginal subseconds
	SUBSECOND_DATETIME_DIGITIZED = 0x9292,	// DateTimeDigitized subseconds
	FLASHPIX_VERSION = 0xA000,	// Supported Flashpix version
	COLOR_SPACE = 0xA001,		// Color space infomation
	PIXEL_X_DIMENSION = 0xA002,	// Valid image width
	PIXEL_Y_DIMENSION = 0xA003,	// Valid image height
	SENSING_METHOD = 0xA217,	// Sensing method
	SCENE_TYPE = 0xA301,		// Scene type
	EXPOSURE_MODE = 0xA402,		// Exposure mode
	WHITE_BALANCE = 0xA403,		// White balance
	FOCAL_LENGTH_IN_35MM_FILM = 0xA405,	// Focal length in 35 mm film
	SCENE_CAPTURE_TYPE = 0xA406,	// Scene capture type
	LENS_SPECIFICATION = 0xA432,	// TBD, Lens Specification (TIFF Tags)
	LENS_MAKER = 0xA433,		// TBD, Lens Maker (TIFF Tags)
	LENS_MODEL = 0xA434			// TBD, Lens Model (TIFF Tags)
};

enum GPS_INFO_IFD_TAGS
{
	LATITUDE_REF = 0x01,	// North or South Latitude
	LATITUDE_VALUE = 0x02,	// Latitude
	LONGTITUDE_REF = 0x03,	// East or West Longtitude
	LONGTITUDE_VALUE = 0x04,	// Longtitude
	ALTITUDE_REF = 0x05,	// Altitude reference
	ALTITUDE_VALUE = 0x06,	// Altitude
	GPS_TIME_STAMP = 0x07,	// GPS time (atomic clock), indicates the time as UTC
	GPS_SPEED_REF = 0x0C,	// Speed unit
	GPS_SPEED_VALUE = 0x0D,	// Speed of GPS receiver
	GPS_IMG_DIRECTION_REF = 0x10,	// Reference for direction of image
	GPS_IMG_DIRECTION_ANGLE = 0x11,	// Direction of image
	GPS_DEST_BEARING_REF = 0x17,	// Reference for bearing of destination
	GPS_DEST_BEARING_ANGLE = 0x18,	// Bearing of destination
	GPS_DATE_STAMP = 0x1D,	// GPS date
	GPS_H_POSITIONING_ERROR = 0x1F	// TBD, GPS horizontal positioning error
};

typedef struct tagTripleRatString
{
	double degre;
	double minute;
	double second;
	std::string ref;
}Latitude, Longtitude;

class ExifInfo
{
public:
	ExifInfo() {}
	~ExifInfo() {}

	friend std::ostream& operator<<(std::ostream& stream, const ExifInfo& info);

	std::string camera_maker;
	std::string camera_model;
	// orientation
	double width_resolution;
	double height_resolution;
	int resolution_unit;
	std::string program_name;
	std::string data_token_datetime;
	// YCbCr positioning
	double exposure_time;
	double F_stop;
	int ISO_speed;
	std::string Exif_version;
	std::string datetime_original;
	std::string datetime_digitized;
	// components configuration
	double shutter_speed;
	Latitude latitude;
	Longtitude longtitude;
};

class CExifReader
{
public:
	CExifReader(LPCTSTR filename);
	~CExifReader();

	bool ReadInfo(ExifInfo& info);
private:
	byte* m_pAppData;
	int IFD0_base;
	int Exif_base;
	int GPS_base;

	void ProceedIFD0(ExifInfo& info);
	void ProceedExif(ExifInfo& info);
	void ProceedGPS(ExifInfo& info);

	Tag FillCurrentTag(byte tag[], int base, size_t index);
	void ForASCII(std::string& str, Tag& tag);
	void ForURational(double* pValue, Tag& tag);
	void ForMultiURational(std::vector<double>& values, Tag& tag);
	void ForSRational(double* pValue, Tag& tag);
	void ForShort(int* pValue, Tag& tag);
	void ForLong(int* pValue, Tag& tag);
};

#endif // Exif_Reader_h__
